---
title: Testing
sidebar_position: 3
description: Testing Mojo programs.
github_url: https://github.com/modular/modular/tree/main/examples/mojo/testing
---

:::caution The `mojo test` command has been removed

The `mojo test` command was removed as of October 31, 2025. For more
information, see the
[deprecation proposal](https://github.com/modular/modular/blob/main/mojo/proposals/mojo-test-deprecation.md)
and
[forum announcement](https://forum.modular.com/t/proposal-deprecating-mojo-test/2371).

The recommended approach for testing is now to use the
[`TestSuite`](/mojo/stdlib/testing/suite/TestSuite) struct from the standard
library, which provides automatic test discovery and execution. Continue reading
for current testing instructions using `TestSuite`.

:::

Mojo includes a framework for developing and executing unit tests. The Mojo
testing framework consists of a set of assertions defined as part of the [Mojo
standard library](/mojo/lib) and the
[`TestSuite`](/mojo/stdlib/testing/suite/TestSuite) struct for automatic test
discovery and execution.

## Get started

Let's start with a simple example of writing and running Mojo tests.

### 1. Write tests

For your first example of using the Mojo testing framework, create a file named
`test_quickstart.mojo` containing the following code:

```mojo
# Content of test_quickstart.mojo
from testing import assert_equal, TestSuite

def inc(n: Int) -> Int:
    return n + 1

def test_inc_zero():
    # This test contains an intentional logical error to show an example of
    # what a test failure looks like at runtime.
    assert_equal(inc(0), 0)

def test_inc_one():
    assert_equal(inc(1), 2)

def main():
    TestSuite.discover_tests[__functions_in_module()]().run()
```

In this file, the `inc()` function is the test *target*. The functions whose
names begin with `test_` are the tests. Usually you should define the target in
a separate source file from its tests, but you can define them in the same file
for this simple example.

A test function *fails* if it raises an error when executed, otherwise it
*passes*. The two tests in this example use the `assert_equal()` function,
which raises an error if the two values provided are not equal.

:::note

The implementation of `test_inc_zero()` contains an intentional logical error
so that you can see an example of a failed test when you execute it in the
next step of this tutorial.

:::

### 2. Execute tests

Then in the directory containing the file, execute the following command in your
shell:

```bash
mojo run test_quickstart.mojo
```

You should see output similar to this (note that this example elides the full
filesystem paths from the output shown):

```output
Unhandled exception caught during execution:
Running 2 tests for ROOT_DIR/test_quickstart.mojo
    FAIL [ 0.009 ] test_inc_zero
      At ROOT_DIR/test_quickstart.mojo:40:5: AssertionError: `left == right` comparison failed:
         left: 1
        right: 0
    PASS [ 0.001 ] test_inc_one
--------
Summary [ 0.009 ] 2 tests run: 1 passed , 1 failed , 0 skipped
Test suite 'ROOT_DIR/test_quickstart.mojo' failed!

mojo: error: execution exited with a non-zero result: 1
```

The output shows each test as it runs with PASS or FAIL status and execution
time, followed by a summary of tests run, passed, failed, and skipped. Failed
tests display their error messages inline.

### Next steps

- [Using Mojo assertion functions](#using-mojo-assertion-functions) describes
  the assertion functions available to help implement tests.
- [Writing unit tests](#writing-unit-tests) shows how to write unit tests and
  organize them into test files.
- Our GitHub repo contains an [example
  project](https://github.com/modular/modular/tree/main/examples/mojo/testing)
  to demonstrate unit testing. Several of the examples shown later are based on
  this project.

## Using Mojo assertion functions

The Mojo standard library includes a [`testing`](/mojo/stdlib/testing/testing/)
module that defines several assertion functions for implementing tests. Each
assertion returns `None` if its condition is met or raises an error if it isn't.

- [`assert_true()`](/mojo/stdlib/testing/testing/assert_true):
  Asserts that the input value is `True`.
- [`assert_false()`](/mojo/stdlib/testing/testing/assert_false):
  Asserts that the input value is `False`.
- [`assert_equal()`](/mojo/stdlib/testing/testing/assert_equal):
  Asserts that the input values are equal.
- [`assert_not_equal()`](/mojo/stdlib/testing/testing/assert_not_equal):
  Asserts that the input values are not equal.
- [`assert_almost_equal()`](/mojo/stdlib/testing/testing/assert_almost_equal):
  Asserts that the input values are equal up to a tolerance.

The boolean assertions report a basic error message when they fail.

```mojo
from testing import *
assert_true(False)
```

```output
Unhandled exception caught during execution

Error: At Expression [1] wrapper:14:16: AssertionError: condition was unexpectedly False
```

Each function also accepts an optional `msg` keyword argument for providing a
custom message to include if the assertion fails.

```mojo
assert_true(False, msg="paradoxes are not allowed")
```

```output
Unhandled exception caught during execution

Error: At Expression [2] wrapper:14:16: AssertionError: paradoxes are not allowed
```

For comparing floating-point values, you should use `assert_almost_equal()`,
which allows you to specify either an absolute or relative tolerance.

```mojo
result = 10 / 3
assert_almost_equal(result, 3.33, atol=0.001, msg="close but no cigar")
```

```output
Unhandled exception caught during execution

Error: At Expression [3] wrapper:15:24: AssertionError: 3.3333333333333335 is not close to 3.3300000000000001 with a diff of 0.0033333333333334103 (close but no cigar)
```

The testing module also defines a [context
manager](/mojo/manual/errors#use-a-context-manager),
[`assert_raises()`](/mojo/stdlib/testing/testing/assert_raises), to assert that
a given code block correctly raises an expected error.

```mojo
def inc(n: Int) -> Int:
    if n == Int.MAX:
         raise Error("inc overflow")
    return n + 1

print("Test passes because the error is raised")
with assert_raises():
    _ = inc(Int.MAX)

print("Test fails because the error isn't raised")
with assert_raises():
    _ = inc(Int.MIN)
```

```output
Unhandled exception caught during execution

Test passes because the error is raised
Test fails because the error isn't raised
Error: AssertionError: Didn't raise at Expression [4] wrapper:18:23
```

:::note

The example above assigns the return value from `inc()` to a
[*discard pattern*](/mojo/manual/lifecycle/death#explicit-lifetime-extension).
Without it, the Mojo compiler reports a warning that the return value is unused.

:::

You can also provide an optional `contains` argument to `assert_raises()` to
indicate that the test passes only if the error message contains the substring
specified. Other errors are propagated, failing the test.

```mojo
print("Test passes because the error contains the substring")
with assert_raises(contains="required"):
    raise Error("missing required argument")

print("Test fails because the error doesn't contain the substring")
with assert_raises(contains="required"):
    raise Error("invalid value")
```

```output
Unhandled exception caught during execution

Test passes because the error contains the substring
Test fails because the error doesn't contain the substring
Error: invalid value
```

## Writing unit tests

A Mojo unit test is simply a function that fulfills all of these requirements:

- Has a name that starts with `test_` for automatic discovery.
- Accepts no arguments.
- Returns `None`.
- Raises an error to indicate test failure.
- Is defined at the module scope, not as a Mojo struct method.

You can use either `def` or `fn` to define a test function. Because a test
function always raises an error to indicate failure, any test function defined
using `fn` must include the `raises` declaration.

Generally, you should use the assertion utilities from the Mojo standard library
[`testing`](/mojo/stdlib/testing/testing/) module to implement your tests.
You can include multiple related assertions in the same test function. However,
if an assertion raises an error during execution, then the test function returns
immediately, skipping any subsequent assertions.

## Running tests with TestSuite

To run your tests, each test file must include a `main()` function that uses
[`TestSuite.discover_tests()`](/mojo/stdlib/testing/suite/TestSuite#discover_tests)
to automatically discover and execute all test functions in the module. The
`__functions_in_module()` compiler intrinsic provides a list of all functions
defined in the current module, which `discover_tests()` filters to find those
with the `test_` prefix.

Here is an example of a test file containing three tests for functions defined
in a source module named `my_target_module` (which is not shown here).

```mojo
# File: test_my_target_module.mojo

from my_target_module import convert_input, validate_input
from testing import assert_equal, assert_false, assert_raises, assert_true, TestSuite

def test_validate_input():
	assert_true(validate_input("good"), msg="'good' should be valid input")
	assert_false(validate_input("bad"), msg="'bad' should be invalid input")

def test_convert_input():
	assert_equal(convert_input("input1"), "output1")
	assert_equal(convert_input("input2"), "output2")

def test_convert_input_error():
	with assert_raises():
		_ = convert_input("garbage")

def main():
	TestSuite.discover_tests[__functions_in_module()]().run()
```

You can then use `mojo run test_my_target_module.mojo` to run the tests and
report the results.
